package com.asggo.g21.aspect;

import com.asggo.g21.ex.G21Exception;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

/**
 * Created by IntelliJ IDEA.
 *
 * @author eric 2024/4/16 9:24
 */
@Aspect
@Component
@Slf4j
public class SignAspect {

  @Before("@annotation(com.asggo.g21.annotation.SignatureValidation)")
  public void signatureValidation(JoinPoint joinPoint) throws JsonProcessingException {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
    HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
    Map<String, String[]> parameterMap = request.getParameterMap();
    log.info("parameter map ->{}", parameterMap);

    log.info("【请求 URL】：{}", request.getRequestURL());
    log.info("【请求 IP】：{}", request.getRemoteAddr());
    log.info("【请求类名】：{}，【请求方法名】：{}", joinPoint.getSignature().getDeclaringTypeName(),
        joinPoint.getSignature().getName());
    final String appId = request.getHeader("demo-appId");
    final String timestamp = request.getHeader("demo-timestamp");
    final String nonce = request.getHeader("demo-nonce");
    log.info("【请求时间】： {} 请求appId {} 请求nonce{}",
        timestamp,
        appId,
        nonce
    );
    ObjectMapper mapper = new ObjectMapper();

    Object[] bodyArgs = joinPoint.getArgs();
    for (Object bodyArg : bodyArgs) {
      if (bodyArg instanceof StandardMultipartHttpServletRequest) {
        continue;
      }

      try {
        final String signBodyArg = sign(bodyArg, appId, timestamp, nonce);
        final String hmacHex = sign(request.getInputStream(), appId, timestamp, nonce);

        log.info("signBodyArg -> {}, body hmac hex --> {}", signBodyArg, hmacHex);

      } catch (IOException e) {
        throw new G21Exception(e);
      }
    }

    log.info("body sign --> {}", request.getHeader("demo-sign"));

    log.info("【请求参数】：{}，", mapper.writeValueAsString(parameterMap));
  }

  private String sign(Object body, String appId, String timestamp, String nonce)
      throws JsonProcessingException {
    String valueToDigest = appId + new ObjectMapper().writeValueAsString(body) + timestamp + nonce;

    return sign(valueToDigest, appId, timestamp, nonce);
  }

  private String sign(InputStream body, String appId, String timestamp, String nonce)
      throws IOException {
    return sign(StreamUtils.copyToString(body, Charset.defaultCharset()), appId, timestamp, nonce);
  }

  private String sign(String body, String appId, String timestamp, String nonce) {
    log.info("body ->{}", body);
    String valueToDigest = appId + body + timestamp + nonce;
    String hmacHex = new HmacUtils(HmacAlgorithms.HMAC_SHA_256,
        "347202c6e1e86fbb70ecs")
        .hmacHex(valueToDigest);

    log.info("body hmac hex --> {}", hmacHex);

    return hmacHex;
  }
}
